﻿using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;

namespace System.Windows {
	public static class DependencyObjectExtension {
		// Validate all dependency objects in a window 
		public static bool IsValid(this DependencyObject node) {
			// Check if dependency object was passed 
			if (node != null) {
				// Check if dependency object is valid. 
				// NOTE: Validation.GetHasError works for controls that have validation rules attached  
				bool isValid = !Validation.GetHasError(node);
				var error = Validation.GetErrors(node);
				if (!isValid) {
					// If the dependency object is invalid, and it can receive the focus, 
					// set the focus 
					if (node is IInputElement)
						Keyboard.Focus((IInputElement)node);
					return false;
				} else {
					// If this dependency object is valid, check all child dependency objects 
					foreach (object subnode in LogicalTreeHelper.GetChildren(node)) {
						if (subnode is DependencyObject) {
							// If a child dependency object is invalid, return false immediately, 
							// otherwise keep checking 
							if (((DependencyObject)subnode).IsValid( ) == false)
								return false;
						}
					}
				}
			}

			// All dependency objects are valid 
			return true;
		}

		public static void TryUpdateSource(this DependencyObject node) {
			//Immediate Properties
			List<FieldInfo> propertiesAll = new List<FieldInfo>( );
			Type currentLevel = node.GetType( );

			while (currentLevel != typeof(object)) {
				propertiesAll.AddRange(currentLevel.GetFields( ));
				currentLevel = currentLevel.BaseType;
			}

			var propertiesDp = propertiesAll.Where(x => x.FieldType == typeof(DependencyProperty));
			foreach (var property in propertiesDp) {
				Binding binding = BindingOperations.GetBinding(node, property.GetValue(node) as DependencyProperty);
				if (binding != null && (binding.Mode == BindingMode.TwoWay || binding.ValidationRules.Count > 0)) {
					BindingExpression expression = BindingOperations.GetBindingExpression(node, property.GetValue(node) as DependencyProperty);
					expression.UpdateSource( );
				}
			}

			foreach (object subnode in LogicalTreeHelper.GetChildren(node)) {
				if (subnode is DependencyObject) {
					// If a child dependency object is invalid, return false immediately, 
					// otherwise keep checking 
					((DependencyObject)subnode).TryUpdateSource( );
				}
			}
		}
	}
}
